/*
    Montage Technology DS2000/RS2000 - DVBS Demodulator/Tuner driver
    Copyright (C) 2009 Wayman Qi <qwm2005@sina.com>

    Copyright (C) 2009 Geniatech

 */

#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/firmware.h>

#include "dvb_frontend.h"
#include "ds2000.h"


#ifndef __QWM_DGB__
#define __QWM_DGB__
#endif

static int debug;

#define dprintk(args...) \
	do { \
		if (debug) \
			printk(args); \
	} while (0)

/* as of March 2009 current DS2000 firmware version is 1.78 */
/* DS2000 FW v1.78 MD5: a32d17910c4f370073f9346e71d34b80 */
#define DS2000_DEFAULT_FIRMWARE "dvb-fe-ds2000.fw"

#define DS2000_SAMPLE_RATE 96000 /* in kHz */
#define DS2000_XTAL_FREQ   27000 /* in kHz */

static int mt_fe_connect_abort = 0;
//static u32	g_auto_tune_cnt    		= 0;
//static u32	g_cci_detect;
//static s32	g_load_firmware			= 0;
static int ds2000_set_demod(struct dvb_frontend *fe, u16 sym_rate_KSs, fe_code_rate_t code_rate);


u32 _mt_mul_div(u32 u, u32 v, u32 z)
{
    u32  u0, v0, w0;
    u32  u1, v1, w1, w2, t;
    u32  x, y;
    s32   i;
    
    // calculate directly, if no overflow for u*v, 
    if( u == (u * (v+1)) / (v+1)) 
    {
        return (u * v) / z;
    }
    
    // Multiplies two big unsigned 32-bit values,
    // the result is a 64-bit value. 
    u0 = u & 0xFFFF;
    u1 = u >> 16;
    v0 = v & 0xFFFF;
    v1 = v >> 16;
    w0 = u0 * v0;
    t  = u1 * v0 + (w0 >> 16);
    w1 = t & 0xFFFF;
    w2 = t >> 16;
    w1 = u0 * v1 + w1;
    
    // x is the high 32-bit integer
    // y is the low 32-bit integer
    x = u1 * v1 + w2 + (w1 >> 16);
    y = u * v;
    
    // Divides the 64-bit result 'x<<32 | y' by 'z'.
    for (i = 1; i <= 32; i++)
    {
        t = (int)x >> 31;                   // All 1's if x(31) = 1.
        
        x = (x << 1) | (y >> 31);           // Shift x || y left
        y <<= 1;                            // one bit.
        
        if((x | t) >= z) 
        {
            x -= z; y++; 
        }
    }
    
    return y;    // y is the quotient, x is the remainder
}


/* DS2000 doesn't need some parameters as input and auto-detects them */
/* save input from the application of those parameters */
struct ds2000_tuning {
	u32 frequency;
	u32 symbol_rate;
	fe_spectral_inversion_t inversion;
	enum fe_code_rate fec;

	/* input values */
	u8 inversion_val;
	fe_modulation_t delivery;
	u8 rolloff;
};

struct ds2000_state {
	struct i2c_adapter *i2c;
	const struct ds2000_config *config;

	struct dvb_frontend frontend;

	struct ds2000_tuning dcur;
	struct ds2000_tuning dnxt;

	u8 skip_fw_load;

	/* previous uncorrected block counter for DVB-S2 */
	u16 prevUCBS2;
};

static int ds2000_writereg(struct ds2000_state *state, int reg, int data)
{
	u8 buf[] = { reg, data };
	struct i2c_msg msg = { .addr = (0xd0 >> 1), //state->config->demod_address,
		.flags = 0, .buf = buf, .len = 2 };
	int err;

	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);

	err = i2c_transfer(state->i2c, &msg, 1);
	if (err != 1) {
		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
			 " value == 0x%02x)\n", __func__, err, reg, data);
		return -EREMOTEIO;
	}

	return 0;
}

static int ds2000_readreg(struct ds2000_state *state, u8 reg)
{
#if 1
	int ret;
	u8 b0[] = { reg };
	u8 b1[] = { 0 };
	struct i2c_msg msg1 = {
			.addr = 0x68, //state->config->demod_address,
			.flags = 0,
			.buf = b0,
			.len = 1
		};
		
	struct i2c_msg msg2 = {
			.addr = 0x68, //state->config->demod_address,
			.flags = I2C_M_RD,
			.buf = b1,
			.len = 1
		};


	ret = i2c_transfer(state->i2c, &msg1, 1);
	if (ret != 1) {
		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
		return ret;
	}
	msleep(1);
	ret = i2c_transfer(state->i2c, &msg2, 1);
	if (ret != 1) {
		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
		return ret;
	}


	dprintk("%s(%d): read reg 0x%02x, value 0x%02x\n", __func__, __LINE__, reg, b1[0]);
#else
	int ret;
	u8 b0[] = { reg };
	u8 b1[] = { 0 };
	struct i2c_msg msg[] = {
		{
			.addr = 0x68, //state->config->demod_address,
			.flags = 0,
			.buf = b0,
			.len = 1
		}, {
			.addr = 0x68, //state->config->demod_address,
			.flags = I2C_M_RD,
			.buf = b1,
			.len = 1
		}
	};

	ret = i2c_transfer(state->i2c, msg, 2);

	if (ret != 2) {
		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
		return ret;
	}

	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
#endif

	return b1[0];
}

static int ds2000_tuner_writereg(struct ds2000_state *state, int reg, int data)
{
	u8 buf[] = { reg, data };
	struct i2c_msg msg = { .addr = 0x60, // 0xC0 >> 1
		.flags = 0, .buf = buf, .len = 2 };
	int err;
	u8 val;

	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
	
	val = ds2000_readreg(state, 0x81);
	val &= ~0x03;
	val |= 0x04;

	ds2000_writereg(state, 0x81, val);
	err = i2c_transfer(state->i2c, &msg, 1);
	if (err != 1) {
		printk("%s: writereg error(err == %i, reg == 0x%02x,"
			 " value == 0x%02x)\n", __func__, err, reg, data);
		return -EREMOTEIO;
	}

	return 0;
}

/* I2C write for 8k firmware load */
static int ds2000_writeFW(struct ds2000_state *state, int reg,
				const u8 *data, u16 len)
{
	int i, ret = -EREMOTEIO;
	struct i2c_msg msg;
	u8 *buf;

	buf = kmalloc(3, GFP_KERNEL);
	if (buf == NULL) {
		printk(KERN_ERR "Unable to kmalloc\n");
		ret = -ENOMEM;
		goto error;
	}

	*(buf) = reg;

	msg.addr = state->config->demod_address;
	msg.flags = 0;
	msg.buf = buf;
	msg.len = 3;

	for (i = 0; i < len; i += 2) {
		memcpy(buf + 1, data + i, 2);

		dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);

		ret = i2c_transfer(state->i2c, &msg, 1);
		if (ret != 1) {
			printk(KERN_ERR "%s: write error(err == %i, "
				"reg == 0x%02x\n", __func__, ret, reg);
			ret = -EREMOTEIO;
		}
	}

error:
	kfree(buf);

	return ret;
}

static int ds2000_tuner_readreg(struct ds2000_state *state, u8 reg)
{
	int ret;
	u8 b0[] = { reg };
	u8 b1[] = { 0 };
	struct i2c_msg msg1 = 
		{
			.addr = 0x60,		// 0xC0 >> 1
			.flags = 0,
			.buf = b0,
			.len = 1
		};
	struct i2c_msg msg2 = 
		{
			.addr = 0x60,		// 0xC0 >> 1
			.flags = I2C_M_RD,
			.buf = b1,
			.len = 1
		};
	u8 val;

	val = ds2000_readreg(state, 0x81);
	val &= ~0x03;
	val |= 0x05;

	ds2000_writereg(state, 0x81, val);
	
	ret = i2c_transfer(state->i2c, &msg1, 1);
	if (ret != 1) {
		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
		return ret;
	}
	msleep(1);
	ret = i2c_transfer(state->i2c, &msg2, 1);
	if (ret != 1) {
		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
		return ret;
	}

	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);

	return b1[0];
}

static int ds2000_set_inversion(struct ds2000_state *state,
					fe_spectral_inversion_t inversion)
{
	dprintk("%s(%d)\n", __func__, inversion);

	switch (inversion) {
	case INVERSION_OFF:
	case INVERSION_ON:
	case INVERSION_AUTO:
		break;
	default:
		return -EINVAL;
	}

	state->dnxt.inversion = inversion;

	return 0;
}

static int ds2000_set_symbolrate(struct ds2000_state *state, u32 rate)
{
	int ret = 0;

#if 0	
	u32	tmp;
	u8	reg_0x61, reg_0x62;

	printk("%s() symbol_rate = %d\n", __func__, rate);
	tmp = (u32)((((rate/1000) << 15) + (DS3000_SAMPLE_RATE / 4)) / (DS3000_SAMPLE_RATE / 2));


	reg_0x61 = (u8)(tmp & 0x00FF);
	reg_0x62 = (u8)((tmp & 0xFF00) >> 8);

	ds3000_writereg(state, 0x61, reg_0x61);
	ds3000_writereg(state, 0x62, reg_0x62);
#endif
	
	state->dnxt.symbol_rate = rate;

	return ret;
}

static int ds2000_soft_reset(struct ds2000_state *state)
{
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************\n", __func__, __LINE__);
#endif
	
	ds2000_writereg(state, 0x9A, 0x30);
	
	ds2000_writereg(state, 0x00, 0x01);
	ds2000_writereg(state, 0x00, 0x00);

	ds2000_writereg(state, 0x9A, 0xB0);

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x9a);
	printk("%s(%d)0x9a = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x00);
	printk("%s(%d)0x00 = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}

static int ds2000_hard_reset(struct ds2000_state *state)
{
	u8 val;

	return 0;
}

static int ds2000_load_firmware(struct dvb_frontend *fe,
					const struct firmware *fw);

static int ds2000_firmware_ondemand(struct dvb_frontend *fe)
{
	struct ds2000_state *state = fe->demodulator_priv;
	const struct firmware *fw;
	int ret = 0;

	dprintk("%s()\n", __func__);
#if 0	
	if (g_load_firmware != 0)
		return 0;

	if (ds2000_readreg(state, 0xb2) <= 0)
		return ret;

	if (state->skip_fw_load)
		return 0;
	/* Load firmware */
	/* request the firmware, this will block until someone uploads it */
	printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
				ds2000_DEFAULT_FIRMWARE);
	ret = request_firmware(&fw, ds2000_DEFAULT_FIRMWARE,
				state->i2c->dev.parent);
	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
	if (ret) {
		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
				"found?)\n", __func__);
		return ret;
	}

	/* Make sure we don't recurse back through here during loading */
	state->skip_fw_load = 1;

	ret = ds2000_load_firmware(fe, fw);
	if (ret)
		printk("%s: Writing firmware to device failed\n", __func__);

	release_firmware(fw);
	

	dprintk("%s: Firmware upload %s\n", __func__,
			ret == 0 ? "complete" : "failed");

	/* Ensure firmware is always loaded if required */
	state->skip_fw_load = 0;
#endif
	return ret;
}

#define FW_DOWN_SIZE	32
#define FW_DOWN_LOOP	(8192/FW_DOWN_SIZE)

static int ds2000_load_firmware(struct dvb_frontend *fe,
					const struct firmware *fw)
{
	struct ds2000_state *state = fe->demodulator_priv;
	u32 i;

	return 0;
}

static void ds2000_dump_registers(struct dvb_frontend *fe)
{
	struct ds2000_state *state = fe->demodulator_priv;
	int x, y, reg = 0, val;

	for (y = 0; y < 16; y++) {
		dprintk("%s: %02x: ", __func__, y);
		for (x = 0; x < 16; x++) {
			reg = (y << 4) + x;
			val = ds2000_readreg(state, reg);
			if (x != 15)
				dprintk("%02x ",  val);
			else
				dprintk("%02x\n", val);
		}
	}
	dprintk("%s: -- ds2000 DUMP DONE --\n", __func__);
}

static int ds2000_read_status(struct dvb_frontend *fe, fe_status_t* status)
{
	struct ds2000_state *state = fe->demodulator_priv;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;

    u8 tmp;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************\n", __func__, __LINE__);
#endif

	tmp = ds2000_readreg(state, 0x8C);

	if ((tmp & 0xEE) == 0xEE)
	{
		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
			FE_HAS_VITERBI | FE_HAS_SYNC |
			FE_HAS_LOCK;
	}
	else
	{
		*status = 0;
	}

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x8C);
	printk("%s(%d)0x8C = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}


//#define BER_CNT_MODE			0		/*	can be 0, 1, 2, 3 or 4	*/
//#define BER_TOTAL_BYTE			(1 << (BER_CNT_MODE * 2 + 12))

/* read ds2000 BER value */
static int ds2000_read_ber(struct dvb_frontend *fe, u32* p_err_bit)
{
	struct ds2000_state *state = fe->demodulator_priv;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	u32 *p_total_bit = 0;
	//u32 *p_err_bit;
#define BER_CNT_MODE                    0               /*      can be 0, 1, 2, 3 or 4  */
#define BER_TOTAL_BYTE                  (1 << (BER_CNT_MODE * 2 + 12))

#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************\n", __func__, __LINE__);
#endif

	static u32	err_bit = 0;
	u8			val_0xd8;
	u8			tmp;
printk("%s(%d)*********************\n", __func__, __LINE__);
	// *p_total_bit = BER_TOTAL_BYTE * 8;
	// *p_total_bit = 96;
printk("%s(%d)*********************\n", __func__, __LINE__);
	*p_err_bit   = err_bit;
printk("%s(%d)*********************\n", __func__, __LINE__);
	ds2000_tuner_writereg(state, 0x9A, 0x30);
printk("%s(%d)*********************\n", __func__, __LINE__);
	val_0xd8 = ds2000_readreg(state, 0xD8);
	if ((val_0xd8 & 0x10) != 0)
	{
		ds2000_tuner_writereg(state, 0x9A, 0xB0);

		return 0;
	}
printk("%s(%d)*********************\n", __func__, __LINE__);
	tmp = ds2000_readreg(state, 0xD7);
	err_bit  = tmp;
	err_bit <<= 8;
	tmp = ds2000_readreg(state, 0xD6);
	err_bit &= 0xff00;
	err_bit += tmp;

	tmp = ds2000_readreg(state, 0xD9);
	tmp &= ~0x07;
	
	ds2000_tuner_writereg(state, 0xD9, (u8)(tmp | BER_CNT_MODE));

	val_0xd8 &= ~0x08;
	val_0xd8 |= 0x30;
	ds2000_tuner_writereg(state, 0xD8, val_0xd8);
	ds2000_tuner_writereg(state, 0xD8, val_0xd8);

	ds2000_tuner_writereg(state, 0x9A, 0xB0);

	*p_err_bit = err_bit;

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x9A);
	printk("%s(%d)0x9A = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xD7);
	printk("%s(%d)0xD7 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xD6);
	printk("%s(%d)0xD6 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xD9);
	printk("%s(%d)0xD9 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xD8);
	printk("%s(%d)0xD8 = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}

static int ds2000_get_signal_gain(struct dvb_frontend *fe, u32* gain)
{
	struct ds2000_state *state = fe->demodulator_priv;

	u8 dwGain1;
	u8 dwGain2;
	u8 dwGain3;
	u8 dwGain4;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************\n", __func__, __LINE__);
#endif

	dwGain1 = ds2000_readreg(state, 0x3D);
	dwGain1 &= 0x1F;
	dwGain2 = ds2000_readreg(state, 0x21);
	dwGain2 &= 0x1F;
	dwGain3 = ds2000_readreg(state, 0x38);
	dwGain3 &= 0x70;
	dwGain3 >>=4;
	dwGain3 &= 0xFF;
	dwGain4 = ds2000_readreg(state, 0x36);

	if(dwGain1 < 0)
		dwGain1 = 0;
	if(dwGain1 > 31)
		dwGain1 = 31;
	if(dwGain2 < 0)
		dwGain2 = 0;
	if(dwGain2 > 15)
		dwGain2 = 15;
	if(dwGain4 < 100)	
		dwGain4 = 100;
	if(dwGain4 > 180)
		dwGain4 = 180;

	*gain = 2026 * dwGain1 + 2995 *dwGain2 + 6000 * (dwGain3 - 1) + 77 * dwGain4;

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x3D);
	printk("%s(%d)0x3D = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x21);
	printk("%s(%d)0x21 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x38);
	printk("%s(%d)0x38 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x36);
	printk("%s(%d)0x36 = 0x%02x\n", __func__, __LINE__, data);
	printk("%s(%d)*gain = %d\n", __func__, __LINE__, *gain);
#endif

	return 0;
}

#define AVG_NUM			1	
/* read TS2020 signal strength */
static int ds2000_read_signal_strength(struct dvb_frontend *fe,
						u16 *signal_strength)
{
	struct ds2000_state *state = fe->demodulator_priv;

	u32 		Gain;
	u16 		i, sum;
	fe_status_t p_lock_state;
	int			bChipLocked;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************\n", __func__, __LINE__);
#endif
	
	static u8 signal_level[16];
	static u8 signal_index = 0;

	ds2000_read_status(fe, &p_lock_state);
	ds2000_get_signal_gain(fe, &Gain);

	bChipLocked = (p_lock_state == (FE_HAS_SIGNAL | FE_HAS_CARRIER |
				FE_HAS_VITERBI | FE_HAS_SYNC |
				FE_HAS_LOCK)) ? 1 : 0;
	
	if(Gain > 80000)	
		*signal_strength = 0;		//0%	no signal or very weak signal;
	else if(Gain > 65000)	
		*signal_strength = 0 + (80000 - Gain) / 230;	//0% ~ 65%	weak signal;
	else if(Gain > 50000)
		*signal_strength = 65 + (65000 - Gain) / 750;	//65% ~ 85%	normal signal;
	else
		*signal_strength = 85 + (50000 - Gain) / 1400;  //85% ~ 100% strong signal;  30000->100%

	if(*signal_strength < 40 && bChipLocked ==  1)	// when the channel locked,set the signal strength bigger
		*signal_strength = 20 + *signal_strength / 2;

	//smooth the shown signal strength, average AVR_NUM times

	signal_level[signal_index] = *signal_strength;
	signal_index ++;
	if(signal_index == 16)
		signal_index = 0;
	
	sum = 0;
	for(i = 0; i < AVG_NUM; i++)
	{
		sum += signal_level[i];
	}
	
	*signal_strength = sum / AVG_NUM;

#ifdef __QWM_DGB__
	printk("%s(%d)*signal_strength = %d\n", __func__, __LINE__, *signal_strength);
#endif
	
	*signal_strength = *signal_strength * 100 / 100;	//SIGNAL_STENGTH_RATIO == 100

	if(*signal_strength > 100)
		*signal_strength = 100;
	if(*signal_strength < 0)
		*signal_strength = 0;

	return 0;
}

/* calculate ds2000 snr value in dB */
static int ds2000_read_snr(struct dvb_frontend *fe, u16 *snr)
{
	struct ds2000_state *state = fe->demodulator_priv;
	//struct dtv_frontend_properties *c = &fe->dtv_property_cache;
#define RETUNER_SNR_AS_PERCENT		0
#define SNT_LOOP					8

    u8	val;
    u32	total_val;
    u8	i;
    
    s32	log_tbl[] = 
    {
		-903,	-204,	051,	211,	327,
		419,	495,	559,	615,	665,
		710,	750,	787,	821,	853,
		882,	910,	936,	960,	983,
		1005,	1026,	1046,	1065,	1084,
		1101,	1118,	1134,	1150,	1165,
		1180,	1194
    };


	total_val = 0;
	for (i = 0; i < SNT_LOOP; i ++) 
	{
		val = ds2000_readreg(state, 0x65);
		total_val += val;
	}

	val = (u8)(total_val / SNT_LOOP);


#if (RETUNER_SNR_AS_PERCENT == 0)

	i = (0 == val) ? 0 : (val / 4 - 1 + ((0 == val % 4) ? 0 : 1));

	if (i >= (sizeof(log_tbl)/sizeof(s32)))
		i = (sizeof(log_tbl)/sizeof(s32));

	*snr = log_tbl[i];

#else

	*snr = val * 100 / 128;

#endif

	return 0;
}

/* read ds2000 uncorrected blocks */
static int ds2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
	struct ds2000_state *state = fe->demodulator_priv;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	u8 val_0xD8, data;
	u16 _ucblocks, tmp1, tmp2;

#ifdef __QWM_DGB__
	printk("%s(%d)*******************\n", __func__, __LINE__);
#endif
	dprintk("%s()\n", __func__);

	// enable error detect
	val_0xD8 = ds2000_readreg(state, 0xd8);
	data = val_0xD8;
	val_0xD8 |= 0x80;
	ds2000_writereg(state, 0xd8, val_0xD8);
	
	tmp1 = ds2000_readreg(state, 0xd5);
	tmp1 = (tmp1 << 8) & 0xff00;
	tmp2 = ds2000_readreg(state, 0xd4);
	tmp2 &= 0x00ff;
	_ucblocks = tmp1 + tmp2;
	
	*ucblocks = _ucblocks;
	ds2000_writereg(state, 0xd8, data);
#ifdef __QWM_DGB__
	printk("%s(%d)ucblocks = %d\n", __func__, __LINE__, *ucblocks);
#endif

	return 0;
}

/* Overwrite the current tuning params, we are about to tune */
static void ds2000_clone_params(struct dvb_frontend *fe)
{
	struct ds2000_state *state = fe->demodulator_priv;
	memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
}

static int ds2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
	struct ds2000_state *state = fe->demodulator_priv;
	u8 val_0xb1, val_0xb2;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************tone=%d\n", __func__, __LINE__,
			tone);
#endif

#if 0
	val_0xb1 = ds2000_readreg(state, 0xb1);
	val_0xb2 = ds2000_readreg(state, 0xb2);

	if (tone == SEC_TONE_ON)
	
	//if (tone == 1 )
printk("%s(%d)************tone enabled, setting tone=%d\n", __func__, __LINE__, tone);

	{
		


	 dprintk("%s: setting tone on\n", __func__);
                 data = ds2000_readreg(state, 0xb1);
                 data &= ~0x43;
                 data |= 0x04;
                 ds3000_writereg(state, 0xb1, data);
		//val_0xb1 |= 0x04;
                //val_0xb1 &= ~0x03;
                //val_0xb1 &= ~0x40;
                //val_0xb2 &= ~0xc0;

		
	

	}
	else
	{
		 //val_0xb2 &= ~0xc0;              // LNB_DISEQC_OUT_FORCE_HIGH 0
                //val_0xb2 |= 0x80;
		

		                 dprintk("%s: setting tone off\n", __func__);
                 data = ds2000_readreg(state, 0xb2);
                 data |= 0x80;
                 ds3000_writereg(state, 0xb2, data);

		
	}

	ds2000_writereg(state, 0xb2, val_0xb2);
	ds2000_writereg(state, 0xb1, val_0xb1);
#endif

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0xb1);
	printk("%s(%d)0xb1 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xb2);
	printk("%s(%d)0xb2 = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}

static int ds2000_send_diseqc_msg(struct dvb_frontend *fe,
				struct dvb_diseqc_master_cmd *d)
{
	struct ds2000_state *state = fe->demodulator_priv;
	int i;
	u8 data;

	/* Dump DiSEqC message */
#ifdef __QWM_DGB__
	printk("%s																																																																																										(%d)*********\n", __func__, __LINE__);
	printk("%s(%d)", __func__, __LINE__);
	for (i = 0 ; i < d->msg_len;) {
		printk("0x%02x", d->msg[i]);
		if (++i < d->msg_len)
			printk(", ");
	}
	printk("\n", __func__, __LINE__);
#endif

	/* enable DiSEqC message send pin */
	data = ds2000_readreg(state, 0xb2);
	data &= ~0xc0;
	ds2000_writereg(state, 0xb2, data);

	/* DiSEqC message */
	for (i = 0; i < d->msg_len; i++)
		ds2000_writereg(state, 0xb3 + i, d->msg[i]);

	data = ds2000_readreg(state, 0xb1);
	
	data &= ~0x38;
	data &= ~0x40;
	data |= ((d->msg_len-1) << 3) | 0x07;

	ds2000_writereg(state, 0xb1, data);

	/* wait up to 150ms for DiSEqC transmission to complete */
	for (i = 0; i < 15; i++) {
		data = ds2000_readreg(state, 0xb1);
		if ((data & 0x40) == 0)
			break;
		msleep(10);
	}

	/* DiSEqC timeout after 150ms */
	if (i == 15) {
		data = ds2000_readreg(state, 0xb1);
		data &= ~0x80;
		data |= 0x40;
		ds2000_writereg(state, 0xb1, data);

		data = ds2000_readreg(state, 0xb2);
		data &= ~0xc0;		//LNB_DISEQC_OUT_FORCE_HIGH 0
		data |= 0x80;
		ds2000_writereg(state, 0xb2, data);

		return 1;
	}

	data = ds2000_readreg(state, 0xb2);
	data &= ~0xc0;
	data |= 0x80;
	ds2000_writereg(state, 0xb2, data);
#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0xb1);
	printk("%s(%d)0xb1 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xb2);
	printk("%s(%d)0xb2 = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}

/* Send DiSEqC burst */
static int ds2000_diseqc_send_burst(struct dvb_frontend *fe,
					fe_sec_mini_cmd_t burst)
{
	struct ds2000_state *state = fe->demodulator_priv;
	u8	val, tmp;
	s32	time_out;

	ds2000_writereg(state, 0x9A, 0x30);


	tmp = ds2000_readreg(state, 0xB2);
	tmp &= ~0xc0;
	ds2000_writereg(state, 0xB2, tmp);

	if (burst == SEC_MINI_B)
		/* Modulated tone burst */
		ds2000_writereg(state, 0xB1, 0x01);
	else if (burst == SEC_MINI_A)
		/* Unmodulated tone burst */
		ds2000_writereg(state, 0xB1, 0x02);

	msleep(13);

	time_out = 5;
	do
	{
		val = ds2000_readreg(state, 0xB1);
		if ((val & 0x40) == 0)
			break;

		msleep(1);
		time_out --;

	} while (time_out > 0);

	//MT_FE_RESET_DiSEqC();
	tmp = ds2000_readreg(state, 0xB1);				\
	tmp &= ~0xc0;								\
	tmp |= 0x40;									\
	ds2000_writereg(state, 0xB1, tmp);				\
												\
	tmp = ds2000_readreg(state, 0xB2);				\
	tmp &= ~0xc0;								\
	tmp |= 0x80;								\
	ds2000_writereg(state, 0xB2, tmp);				\
												\
	ds2000_writereg(state, 0x9A, 0xB0);				\

	if (time_out <= 0)
		return -1;

	return 0;
}





// qwm add at 2010.4.21
static int ds2000_set_LNB(struct ds2000_state *state, 
	s32 is_LNB_enable, s32 is_22k_enable, fe_sec_voltage_t voltage_type)
{
    u8 val_0xb1, val_0xb2;

#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************is_LNB_enable=%d, is_22k_enable=%d, voltage_type=%d\n", __func__, __LINE__,
			is_LNB_enable, is_22k_enable, (int)voltage_type);
#endif
        
	ds2000_writereg(state, 0x9A, 0x30);

	ds2000_writereg(state, 0xB1, &val_0xb1);
	ds2000_writereg(state, 0xB2, &val_0xb2);

	if (!is_LNB_enable)
	{
		val_0xb1 |= 0x40;

		
		/*	set LNB_EN pin HIGH or LOW	*/
		#if 0	//(MT_FE_PIN_LNB_EN_LEVEL_WHEN_LNB_ENABLE)
		val_0xb2 &= ~0x02;
		#else
		val_0xb2 |= 0x02;
		#endif


		/*	set V_SEL Pin mode			*/
		#if 1	//(MT_FE_PIN_VSEL_LEVEL_WHEN_LNB_STANDBY)
	/*	val_0xb2 |= 0x01;
		#else
		val_0xb2 &= ~0x01;
	*/	#endif


		/*	set DiseQc_OUT mode			*/
		#if 0	//(MT_FE_PIN_DISEQC_OUT_LEVEL_WHEN_LNB_STANDBY)
		val_0xb2 |= 0xc0;
		#else
		val_0xb2 &= ~0xc0;
		val_0xb2 |= 0x80;
		#endif
	}
	else
	{
		#if 0	//(MT_FE_PIN_LNB_EN_LEVEL_WHEN_LNB_ENABLE)
	/*	val_0xb2 |= 0x02;
		#else
		val_0xb2 &= ~0x02;
	*/	#endif



		#if 1	//(MT_FE_PIN_VSEL_LEVEL_WHEN_LNB_13V)
	/*	if (voltage_type == SEC_VOLTAGE_13)
			val_0xb2 |= 0x01;
		else
			val_0xb2 &= ~0x01;
		#else
		if (voltage_type == SEC_VOLTAGE_13)
			val_0xb2 &= ~0x01;
		else
			val_0xb2 |= 0x01;
	*/	#endif


		if (is_22k_enable)
		{
			val_0xb1 |= 0x04;
			val_0xb1 &= ~0x03;
			val_0xb1 &= ~0x40;
			val_0xb2 &= ~0xc0;
		}
		else
		{
			#if 0	//(MT_FE_PIN_DISEQC_OUT_LEVEL_WHEN_LNB_STANDBY)
			val_0xb2 |= 0xc0;
			#else
			val_0xb2 &= ~0xc0;
			val_0xb2 |= 0x80;
			#endif
		}
	}

	/*	must set register 0xB2 first	*/
	ds2000_writereg(state, 0xB2, val_0xb2);
	ds2000_writereg(state, 0xB1, val_0xb1);

	ds2000_writereg(state, 0x9A, 0xB0);

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x9A);
	printk("%s(%d)0x9A = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xb1);
	printk("%s(%d)0xb1 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xb2);
	printk("%s(%d)0xb2 = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}


static int ds2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
	struct ds2000_state *state = fe->demodulator_priv;
	u8 data;

	 dprintk("%s\n", __func__);


	data = ds2000_readreg(state, 0xa2);
	data |= 0x03; /* bit0 V/H, bit1 off/on */

	switch (voltage) {
	case SEC_VOLTAGE_18:
		data &= ~0x03;
		break;
	case SEC_VOLTAGE_13:
		data &= ~0x03;
		data |= 0x01;
		break;
	case SEC_VOLTAGE_OFF:
		break;
	}

	ds2000_writereg(state, 0xB2, data);

	return 0;
}








static void ds2000_release(struct dvb_frontend *fe)
{
	struct ds2000_state *state = fe->demodulator_priv;
	dprintk("%s\n", __func__);
	
	// qwm add 2010.4.21
	//ds2000_set_LNB(state, 0, 0, fe->dtv_property_cache.voltage);

	kfree(state);
}


static int ds2000_set_property(struct dvb_frontend *fe,
	struct dtv_property *tvp)
{
#ifdef __QWM_DGB__
	printk("%s(%d)*******\n", __func__, __LINE__);
#endif
	dprintk("%s(..)\n", __func__);
	return 0;
}

static int ds2000_get_property(struct dvb_frontend *fe,
	struct dtv_property *tvp)
{
	dprintk("%s(..)\n", __func__);
	return 0;
}

// qwm add at 2010.4.12. Equal _mt_fe_dmd_ds3k_set_ts_out_mode
static int ds2000_set_ts_out(struct dvb_frontend *fe, int mode)
{
	struct ds2000_state *state = fe->demodulator_priv;
	u8 tmp, val_0x08, buf;
	
	
	return 0;
}

static int ds2000_tuner_init(struct dvb_frontend *fe)
{
	struct ds2000_state *state = fe->demodulator_priv;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************\n", __func__, __LINE__);
#endif
	
	ds2000_tuner_writereg(state, 0x42, 0x73);
   	ds2000_tuner_writereg(state, 0x05, 0x07);
	ds2000_tuner_writereg(state, 0x20, 0x27);
	ds2000_tuner_writereg(state, 0x07, 0x02);
	ds2000_tuner_writereg(state, 0x11, 0xff);
	ds2000_tuner_writereg(state, 0x60, 0xF9);
	ds2000_tuner_writereg(state, 0x08, 0x01);
	ds2000_tuner_writereg(state, 0x00, 0x41);

#ifdef __QWM_DGB__
	data = ds2000_tuner_readreg(state, 0x42);
	printk("%s(%d)0x42 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x05);
	printk("%s(%d)0x05 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x20);
	printk("%s(%d)0x20 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x07);
	printk("%s(%d)0x07 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x11);
	printk("%s(%d)0x11 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x60);
	printk("%s(%d)0x60 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x08);
	printk("%s(%d)0x08 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x00);
	printk("%s(%d)0x00 = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}

#define MT_RS2K_CRYSTAL_MHZ			27
#define MT_RS2K_CRYSTAL_KHZ			27000
static int ds2000_tuner_set_freq(struct dvb_frontend *fe, u32 freq_KHz, s16 *p_offset_KHz)
{
	struct ds2000_state *state = fe->demodulator_priv;

	u8	tmp;
    u8	K, div4;
    u16	N;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************freq_KHz=%d\n", __func__, __LINE__, freq_KHz);
#endif

	/*
		Set PLL
	*/
	K = (u8)(((MT_RS2K_CRYSTAL_MHZ + 1) / 2) - 8);
	N = (u16)((freq_KHz * (K + 8) * 2 + MT_RS2K_CRYSTAL_KHZ / 2) / MT_RS2K_CRYSTAL_KHZ);

	if (N < 1100)
	{
		tmp  = 0x91;
		div4 = 1;
		N    = (u32)(((freq_KHz * (K + 8) * 4 + MT_RS2K_CRYSTAL_KHZ / 2)  / MT_RS2K_CRYSTAL_KHZ) - 1024);

		*p_offset_KHz = (s32)((N + 1024) * MT_RS2K_CRYSTAL_KHZ / ((K + 8) * (div4 + 1) * 2)  - freq_KHz);
	}
	else
	{
		tmp  = 0x81;
		div4 = 0;
		N   -= 1024;

		*p_offset_KHz = (s32)((N - N % 2 + 1024) * MT_RS2K_CRYSTAL_KHZ / ((K + 8) * (div4 + 1) * 2)  - freq_KHz);
	}
	ds2000_tuner_writereg(state, 0x10, tmp);

#ifdef __QWM_DGB__
	printk("%s(%d)*********************p_offset_KHz=%d\n", __func__, __LINE__, *p_offset_KHz);
#endif

	ds2000_tuner_writereg(state, 0x01, (u8)((N >> 8) & 0x0f));
	ds2000_tuner_writereg(state, 0x02, (u8)((N >> 0) & 0xff));
	ds2000_tuner_writereg(state, 0x03, K);

	/*
		Call PLL
	*/
	ds2000_tuner_writereg(state, 0x51, 0x0F);
	ds2000_tuner_writereg(state, 0x51, 0x1F);
	ds2000_tuner_writereg(state, 0x50, 0x10);
	ds2000_tuner_writereg(state, 0x50, 0x00);

	msleep(5);

	tmp = ds2000_tuner_readreg(state, 0x10);
	tmp = ds2000_tuner_readreg(state, 0x10); //, (U8)(tmp & 0x7F));
	tmp &= 0x7F;

#ifdef __QWM_DGB__
	data = ds2000_tuner_readreg(state, 0x01);
	printk("%s(%d)0x01 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x02);
	printk("%s(%d)0x20 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x03);
	printk("%s(%d)0x03 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x51);
	printk("%s(%d)0x51 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x50);
	printk("%s(%d)0x50 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x10);
	printk("%s(%d)0x10 = 0x%02x\n", __func__, __LINE__, data);
#endif
	
	return 0;
}

static int ds2000_tuner_lpf(struct dvb_frontend *fe, u32 sym_rate_KSs, s16 lpf_offset_KHz)
{
	struct ds2000_state *state = fe->demodulator_priv;
	u8	tmp;
	u16	f3dB, gdiv28;
	u16	lpf_gm, lpf_mxdiv;
	u16	divMax, divMin;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************sym_rate_KSs = %d, lpf_offset_KHz = %d\n", __func__, __LINE__,
			sym_rate_KSs, lpf_offset_KHz);
#endif

	f3dB = (u16)((8 * sym_rate_KSs) / 10 + 2000 + lpf_offset_KHz);
	if (f3dB < 7000)
		f3dB = 7000;
	
	gdiv28 = (u16)((1694 * MT_RS2K_CRYSTAL_MHZ + 500) / 1000);
	tmp    = (u8)gdiv28;
#ifdef __QWM_DGB__
	printk("%s(%d)gdiv28 = %d\n", __func__, __LINE__, gdiv28);
#endif
	ds2000_tuner_writereg(state, 0x04, tmp);

	ds2000_tuner_writereg(state, 0x51, 0x1b);
	ds2000_tuner_writereg(state, 0x51, 0x1f);
	ds2000_tuner_writereg(state, 0x50, 0x04);
	ds2000_tuner_writereg(state, 0x50, 0x00);

	msleep(5);

	tmp = ds2000_tuner_readreg(state, 0x26); 

	gdiv28 = (u16)(gdiv28 * 1035 / (tmp * 10 + 755));
	divMax = (u16)((gdiv28 * 135) / 100);
	divMin = (u16)((gdiv28 * 78) / 100);

	if (divMax > 63 )
		divMax = 63;


	lpf_gm = (u16)((f3dB * gdiv28 + (2766 * MT_RS2K_CRYSTAL_MHZ) / 2) / (2766 * MT_RS2K_CRYSTAL_MHZ));
	if (lpf_gm > 23)
		lpf_gm = 23;
	if (lpf_gm < 1)
		lpf_gm = 1;


	lpf_mxdiv = (u16)((lpf_gm * MT_RS2K_CRYSTAL_MHZ * 2766 + (f3dB) / 2) / (f3dB));

	if (lpf_mxdiv < divMin)
	{
		lpf_gm++;
		lpf_mxdiv = (u16)((lpf_gm * MT_RS2K_CRYSTAL_MHZ * 2766 + f3dB / 2) / f3dB);
	}

	if (lpf_mxdiv > divMax)
		lpf_mxdiv = divMax;

	tmp = (u8) lpf_mxdiv;
	ds2000_tuner_writereg(state, 0x04, tmp);

	tmp = (u8) lpf_gm;
	ds2000_tuner_writereg(state, 0x06, tmp);

	ds2000_tuner_writereg(state, 0x51, 0x1b);
	ds2000_tuner_writereg(state, 0x51, 0x1f);
	ds2000_tuner_writereg(state, 0x50, 0x04);
	ds2000_tuner_writereg(state, 0x50, 0x00);

	msleep(5);

#ifdef __QWM_DGB__
	data = ds2000_tuner_readreg(state, 0x04);
	printk("%s(%d)0x04 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x51);
	printk("%s(%d)0x51 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x50);
	printk("%s(%d)0x50 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x06);
	printk("%s(%d)0x06 = 0x%02x\n", __func__, __LINE__, data);
#endif
	
	return 0;
}

//static s32 g_tuner_freq_offset_KHz;
static int ds2000_set_tuner(struct dvb_frontend *fe, u32 freq_KHz, u32 sym_rate_KSs, s16 lpf_offset_KHz, s16 *p_offset_KHz)
{
	struct ds2000_state *state = fe->demodulator_priv;
	u8	tmp;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************freq_KHz=%d, sym_rate_KSs=%d, lpf_offset_KHz=%d\n", __func__, __LINE__,
			freq_KHz, sym_rate_KSs, lpf_offset_KHz);
#endif

	// equal 'mt_fe_tn_init_ts2020', ds2000_attach already does it
	//ds2000_tuner_init(state);

	/*	Set PLL	*/
	//_mt_fe_rs2k_tuner_set_freq(freq_KHz, p_offset_KHz);
	ds2000_tuner_set_freq(fe, freq_KHz, p_offset_KHz);

	ds2000_tuner_writereg(state, 0x51, 0x17);
	ds2000_tuner_writereg(state, 0x51, 0x1f);
	ds2000_tuner_writereg(state, 0x50, 0x08);
	ds2000_tuner_writereg(state, 0x50, 0x00);

	msleep(5);

	if (freq_KHz >= 1550*1000)
	{
		tmp = ds2000_tuner_readreg(state, 0x3d);
		tmp &= 0x1f;
		if ((tmp > 12) && (tmp < 31))
		{
			tmp = (((tmp - 2) << 3) | 0x01) & 0xf9;
			ds2000_tuner_writereg(state, 0x60, tmp);

			ds2000_tuner_writereg(state, 0x51, 0x17);
			ds2000_tuner_writereg(state, 0x51, 0x1f);
			ds2000_tuner_writereg(state, 0x50, 0x08);
			ds2000_tuner_writereg(state, 0x50, 0x00);
		}
	}

	//_mt_fe_rs2k_tuner_lpf(sym_rate_KSs, lpf_offset_KHz);
	ds2000_tuner_lpf(fe, sym_rate_KSs, lpf_offset_KHz);

	ds2000_tuner_writereg(state, 0x51, 0x1e);
	ds2000_tuner_writereg(state, 0x51, 0x1f);
	ds2000_tuner_writereg(state, 0x50, 0x01);
	ds2000_tuner_writereg(state, 0x50, 0x00);

	msleep(80);

#ifdef __QWM_DGB__
	data = ds2000_tuner_readreg(state, 0x51);
	printk("%s(%d)0x51 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_tuner_readreg(state, 0x50);
	printk("%s(%d)0x50 = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}

static int ds2000_set_carrier_offset(struct dvb_frontend *fe, s16 offset_KHz)
{
	struct ds2000_state *state = fe->demodulator_priv;

#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************offset_KHz=%d\n", __func__, __LINE__,
			offset_KHz);
#endif

	s32	val;
	u8	tmp;
	u8	reg_val;
	u32	M_clk;

	reg_val = ds2000_readreg(state, 0x86);
	printk("%s(%d)0x86 = 0x%02x\n", __func__, __LINE__, reg_val);
	M_clk = ((reg_val/2 + 1) * 27000 + 28/2) / 28;

	val = (offset_KHz * 4096 + (s32)M_clk / 2) / (s32)M_clk;

	printk("%s(%d)val = %d\n", __func__, __LINE__, val);

	if (val < 0)
		val += 4096;
	printk("%s(%d)val >> 4 = %d\n", __func__, __LINE__, val >> 4);

	ds2000_writereg(state, 0x9C, (u8)(val >> 4));
	tmp = ds2000_readreg(state, 0x9D);
	printk("%s(%d)tmp = %d\n", __func__, __LINE__, tmp);
	tmp = (u8)((val & 0x0F) << 4 | tmp & 0x0F);
	printk("%s(%d)tmp = %d\n", __func__, __LINE__, tmp);
	ds2000_writereg(state, 0x9D, tmp);

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x9C);
	printk("%s(%d)0x9C = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x9D);
	printk("%s(%d)0x9D = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}

static int ds2000_set_demod(struct dvb_frontend *fe, u16 sym_rate_KSs, fe_code_rate_t code_rate)
{
	struct ds2000_state *state = fe->demodulator_priv;
	u8   val;
	u32  tmp;
	u8	 reg_val;
	u32  M_clk;
#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************sym_rate_KSs=%d, code_rate=%d\n", __func__, __LINE__,
			sym_rate_KSs, code_rate);
#endif


	if (sym_rate_KSs > 27500)
		ds2000_writereg(state, 0xF1, 0xA4);
	else
		ds2000_writereg(state, 0xF1, 0xBF);

	ds2000_writereg(state, 0x00, 0x01);
	ds2000_writereg(state, 0x20, 0x81);
	ds2000_writereg(state, 0x21, 0x80);
	ds2000_writereg(state, 0x10, 0x33);
	ds2000_writereg(state, 0x11, 0x44);
	ds2000_writereg(state, 0x12, 0x07);
	ds2000_writereg(state, 0x18, 0x20);
	ds2000_writereg(state, 0x28, 0x04);
	ds2000_writereg(state, 0x29, 0x8E);
	ds2000_writereg(state, 0x3B, 0xFF);
	ds2000_writereg(state, 0x32, 0x10);
	ds2000_writereg(state, 0x33, 0x02);
	ds2000_writereg(state, 0x34, 0x30);
	ds2000_writereg(state, 0x35, 0xFF);
	ds2000_writereg(state, 0x38, 0x50);
	ds2000_writereg(state, 0x39, 0x68);
	ds2000_writereg(state, 0x3C, 0x7F);
	ds2000_writereg(state, 0x3D, 0x0F);
	ds2000_writereg(state, 0x45, 0x20);
	ds2000_writereg(state, 0x46, 0x30);
	ds2000_writereg(state, 0x47, 0x7C);
	ds2000_writereg(state, 0x48, 0x16);
	ds2000_writereg(state, 0x49, 0x04);
	ds2000_writereg(state, 0x4A, 0x01);
	ds2000_writereg(state, 0x4B, 0x78);
	ds2000_writereg(state, 0x4D, 0xD2);
	ds2000_writereg(state, 0x4E, 0x6D);
	ds2000_writereg(state, 0x50, 0x30);
	ds2000_writereg(state, 0x51, 0x30);
	ds2000_writereg(state, 0x54, 0x7B);
	ds2000_writereg(state, 0x56, 0x09);
	ds2000_writereg(state, 0x58, 0x59);
	ds2000_writereg(state, 0x59, 0x37);
	ds2000_writereg(state, 0x63, 0xFA);


	/*	set code rate
	*/
	//if (code_rate == FEC_NONE)
		code_rate = 0xf8; //FEC_AUTO;//MtFeRs2kCodeRateSel_All;

	val = ds2000_readreg(state, 0x70);
	printk("%s(%d)0x70 = 0x%02x\n", __func__, __LINE__, val);
	val &= ~0xf8;
	printk("%s(%d)val = 0x%02x\n", __func__, __LINE__, val);
	ds2000_writereg(state, 0x70, (u8)(val | code_rate));

	ds2000_writereg(state, 0x85, 0x01);
	ds2000_writereg(state, 0x8A, 0xBF);
	ds2000_writereg(state, 0x8D, 0x1E);
	ds2000_writereg(state, 0x90, 0xF1);
	ds2000_writereg(state, 0x91, 0x08);

	/*	Set symbol rate
	*/
	reg_val = ds2000_readreg(state, 0x86);
	M_clk = ((reg_val/2 + 1) * MT_RS2K_CRYSTAL_KHZ + 28/2) / 28;

	tmp = _mt_mul_div(sym_rate_KSs, 0x01 << 24, M_clk);
	val = (u8)(tmp & 0xFF);
	ds2000_writereg(state, 0x93, val);
	val = (u8)((tmp >> 8) & 0xFF);
	ds2000_writereg(state, 0x94, val);
	val = (u8)((tmp >> 16) & 0xFF);
	ds2000_writereg(state, 0x95, val);



	ds2000_writereg(state, 0x97, 0x04);
	ds2000_writereg(state, 0x99, 0x77);
	ds2000_writereg(state, 0x9A, 0xB0);
	ds2000_writereg(state, 0x9B, 0x64);
	ds2000_writereg(state, 0x9E, 0x00);
	ds2000_writereg(state, 0x9F, 0xF8);

	val = (sym_rate_KSs > 10000) ? 0x20 : 0x60;
	ds2000_writereg(state, 0xA0, val);
	ds2000_writereg(state, 0xA1, 0xE0);

	if(sym_rate_KSs > 12000)
	{
		ds2000_writereg(state, 0xA3, 0x38);
	}
	else if(sym_rate_KSs > 6000)
	{
		ds2000_writereg(state, 0xA3, 0x98);
	}
	else
	{
		ds2000_writereg(state, 0xA3, 0x90);
	}
	
	ds2000_writereg(state, 0x98, 0xFF);
	ds2000_writereg(state, 0xC0, 0x0F);
	ds2000_writereg(state, 0x89, 0x01);
	ds2000_writereg(state, 0x00, 0x00);

	msleep(20);

	ds2000_writereg(state, 0x00, 0x01);
	ds2000_writereg(state, 0x00, 0x00);

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0xf1);
	printk("%s(%d)0xf1 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x00);
	printk("%s(%d)0x00 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x20);
	printk("%s(%d)0x20 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x21);
	printk("%s(%d)0x21 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x10);
	printk("%s(%d)0x10 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x11);
	printk("%s(%d)0x11 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x12);
	printk("%s(%d)0x12 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x18);
	printk("%s(%d)0x18 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x28);
	printk("%s(%d)0x28 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x29);
	printk("%s(%d)0x29 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x3b);
	printk("%s(%d)0x3b = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x32);
	printk("%s(%d)0x32 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x33);
	printk("%s(%d)0x33 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x34);
	printk("%s(%d)0x34 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x35);
	printk("%s(%d)0x35 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x38);
	printk("%s(%d)0x38 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x39);
	printk("%s(%d)0x39 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x3c);
	printk("%s(%d)0x3c = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x3d);
	printk("%s(%d)0x3d = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x45);
	printk("%s(%d)0x45 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x46);
	printk("%s(%d)0x46 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x47);
	printk("%s(%d)0x47 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x48);
	printk("%s(%d)0x48 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x49);
	printk("%s(%d)0x49 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x4a);
	printk("%s(%d)0x4a = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x4b);
	printk("%s(%d)0x4b = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x4d);
	printk("%s(%d)0x4d = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x4e);
	printk("%s(%d)0x4e = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x50);
	printk("%s(%d)0x50 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x51);
	printk("%s(%d)0x51 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x54);
	printk("%s(%d)0x54 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x56);
	printk("%s(%d)0x56 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x58);
	printk("%s(%d)0x58 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x59);
	printk("%s(%d)0x59 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x63);
	printk("%s(%d)0x63 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x70);
	printk("%s(%d)0x70 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x85);
	printk("%s(%d)0x85 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x8a);
	printk("%s(%d)0x8a = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x8b);
	printk("%s(%d)0x8b = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x8d);
	printk("%s(%d)0x8d = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x90);
	printk("%s(%d)0x90 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x91);
	printk("%s(%d)0x91 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x93);
	printk("%s(%d)0x93 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x94);
	printk("%s(%d)0x94 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x97);
	printk("%s(%d)0x97 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x99);
	printk("%s(%d)0x99 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x9a);
	printk("%s(%d)0x9a = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x9b);
	printk("%s(%d)0x9b = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x9e);
	printk("%s(%d)0x9e = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x9f);
	printk("%s(%d)0x9f = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xa0);
	printk("%s(%d)0xa0 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xa1);
	printk("%s(%d)0xa1 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xa3);
	printk("%s(%d)0xa3 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x98);
	printk("%s(%d)0x98 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xc0);
	printk("%s(%d)0xc0 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x89);
	printk("%s(%d)0x89 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x00);
	printk("%s(%d)0x00 = 0x%02x\n", __func__, __LINE__, data);
#endif

	return 0;
}

static int ds2000_tune(struct dvb_frontend *fe,
				struct dvb_frontend_parameters *p)
{
	struct ds2000_state *state = fe->demodulator_priv;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	int ret = 0, retune, i;
	s16					freq_offset;
	s16					lpf_offset;
	s32					time_out;
	u8					tmp;
	u32					freq_KHz;
	u32					frequency_KHz;
	u16					sym_rate_KSs;
	fe_code_rate_t		code_rate;
	fe_status_t			lock_state;

#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************\n", __func__, __LINE__);
#endif

	/* Load the firmware if required */
	// todo

	state->dnxt.delivery = c->modulation;
	state->dnxt.frequency = c->frequency;
	state->dnxt.rolloff = 2; /* fixme */
	state->dnxt.fec = c->fec_inner;

	ret = ds2000_set_inversion(state, p->inversion);
	if (ret !=  0)
		return ret;
	
	ret = ds2000_set_symbolrate(state, c->symbol_rate);
	if (ret !=  0)
		return ret;

	ds2000_clone_params(fe);

	frequency_KHz = state->dcur.frequency;
	sym_rate_KSs = state->dcur.symbol_rate/1000;
	code_rate = state->dcur.fec;	//c->fec_inner;
#ifdef __QWM_DGB__
	printk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
	printk("%s:   sym_rate_KSs = %d\n", __func__, state->dcur.symbol_rate);
	printk("%s:   code_rate	 = %d \n", __func__, state->dcur.fec);
	printk("%s:   Inversion   = %d\n", __func__, state->dcur.inversion);
#endif
	freq_KHz = frequency_KHz;
	
	// mt_fe_rs2k_connect
	freq_offset = 0;
	lpf_offset  = 0;
	if (state->dcur.symbol_rate/1000 < 5000)
	{
		lpf_offset = 3000; //FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
		freq_KHz  += 3000; //FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
	}

	//ds2000_set_LNB(state, 1, 1, fe->dtv_property_cache.voltage);
	//	ds2000_set_LNB(state, 1, 1, 1);

	//_mt_fe_rs2k_tuner_set_channel(freq_KHz, sym_rate_KSs, lpf_offset, &freq_offset);
	ds2000_set_tuner(fe, state->dcur.frequency, 
						 state->dcur.symbol_rate/1000, 
						 lpf_offset, &freq_offset);

	ds2000_writereg(state, 0x9A, 0x30);
	
	if(((frequency_KHz % 192857) >= (192857 - 3000)) || (frequency_KHz % 192857) <= 3000)	//96.4285*2*1000 = 192857
		ds2000_writereg(state, 0x86, 0xC2);
	else
		ds2000_writereg(state, 0x86, 0xC6);

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x9A);
	printk("%s(%d)0x9A = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x86);
	printk("%s(%d)0x86 = 0x%02x\n", __func__, __LINE__, data);
	printk("%s(%d)freq_offset = %d, freq_KHz = %d, frequency_KHz = %d\n", __func__, __LINE__, 
			freq_offset, freq_KHz, frequency_KHz);
#endif
		
	//_mt_fe_rs2k_set_carrier_offset((S16)(freq_offset + (freq_KHz - frequency_KHz)));
	ds2000_set_carrier_offset(fe, (s16)(freq_offset + (freq_KHz - frequency_KHz)));
	
	//_mt_fe_rs2k_set_demod(sym_rate_KSs, code_rate);
	ds2000_set_demod(fe, sym_rate_KSs, code_rate);

	if (sym_rate_KSs < 2000)
		time_out = 3000;
	else
		time_out = 1000;

	while (time_out > 0)
	{
		ds2000_read_status(fe, &lock_state);
		if (lock_state == FE_HAS_SIGNAL | FE_HAS_CARRIER |
			FE_HAS_VITERBI | FE_HAS_SYNC |
			FE_HAS_LOCK) //MtFeLockState_Locked)
		{
			//*p_lock_state = lock_state;
			return 0;
		}

		if (mt_fe_connect_abort)
		{
			mt_fe_connect_abort = 0;
			return 1; //MtFeRet_Abort;
		}

		msleep(50);
		time_out -= 50;
	}

	tmp = ds2000_readreg(state, 0x70);
	tmp = (u8)(((~tmp) & 0x04) | (tmp & 0xFB));
	ds2000_writereg(state, 0x70, tmp);

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x70);
	printk("%s(%d)0x70 = 0x%02x\n", __func__, __LINE__, data);
#endif

	time_out = 400;
	while (time_out > 0)
	{
		ds2000_read_status(fe, &lock_state);
		if (lock_state == FE_HAS_SIGNAL | FE_HAS_CARRIER |
			FE_HAS_VITERBI | FE_HAS_SYNC |
			FE_HAS_LOCK) //MtFeLockState_Locked)
		{
			//*p_lock_state = lock_state;
			return 0; //MtFeRet_Succeed;
		}

		if (mt_fe_connect_abort)
		{
			mt_fe_connect_abort = 0;
			return 1; //MtFeRet_Abort;
		}

		msleep(50);
		time_out -= 50;
	}

	return ret;
}

static enum dvbfe_algo ds2000_get_algo(struct dvb_frontend *fe)
{
	dprintk("%s()\n", __func__);
	return DVBFE_ALGO_SW;
}

/*
 * Initialise or wake up device
 *
 * Power config will reset and load initial firmware if required
 */
static int ds2000_initfe(struct dvb_frontend *fe)
{
	struct ds2000_state *state = fe->demodulator_priv;

#ifdef __QWM_DGB__
	printk("%s(%d)***********************\n", __func__, __LINE__);
#endif
	dprintk("%s()\n", __func__);

	return 0;
}

static struct dvb_frontend_ops ds2000_ops;

struct dvb_frontend *ds2000_attach(const struct ds2000_config *config,
				    struct i2c_adapter *i2c)
{
	struct ds2000_state *state = NULL;
	int ret;

#ifdef __QWM_DGB__
	u8	data;
	printk("%s(%d)*********************\n", __func__, __LINE__);
#endif

	dprintk("%s\n", __func__);
	
	mt_fe_connect_abort = 0;
	
	/* allocate memory for the internal state */
	state = kmalloc(sizeof(struct ds2000_state), GFP_KERNEL);
	if (state == NULL) {
		printk(KERN_ERR "Unable to kmalloc\n");
		goto error2;
	}

	/* setup the state */
	memset(state, 0, sizeof(struct ds2000_state));

	state->config = config;
	state->i2c = i2c;
	state->prevUCBS2 = 0;

	/* check if the demod is present */
	ret = ds2000_readreg(state, 0x00);
	printk("%s(%d)0x00 = 0x%02x\n", __func__, __LINE__, ret);
	ret &= 0xfe;
	/*if (ret != 0x02) {		// chip id
		printk(KERN_ERR "Invalid probe, probably not a DS2000\n");
		goto error3;
	}*/
	
	printk(KERN_INFO "DS2000 chip attached.\n");

	memcpy(&state->frontend.ops, &ds2000_ops,
			sizeof(struct dvb_frontend_ops));
	state->frontend.demodulator_priv = state;
	
#if 1
	//mt_fe_rs2k_init
	ds2000_tuner_init(&state->frontend);

	ds2000_writereg(state, 0x81, 0x81);
	ds2000_writereg(state, 0x86, 0xC6);

	ds2000_writereg(state, 0x9A, 0x30);
	
	//mt_fe_r22k_set_ts_mode();
	ds2000_writereg(state, 0xF0, 0x80);
	ds2000_writereg(state, 0xF1, 0xBF);

	ds2000_writereg(state, 0xB0, 0x45);

	ds2000_writereg(state, 0x9A, 0xB0);
	// end mt_fe_rs2k_init
#endif

#ifdef __QWM_DGB__
	data = ds2000_readreg(state, 0x00);
	printk("%s(%d)0x00 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x81);
	printk("%s(%d)0x81 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x86);
	printk("%s(%d)0x86 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0x9a);
	printk("%s(%d)0x9a = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xf0);
	printk("%s(%d)0xf0 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xf1);
	printk("%s(%d)0xf1 = 0x%02x\n", __func__, __LINE__, data);
	data = ds2000_readreg(state, 0xb0);
	printk("%s(%d)0xb0 = 0x%02x\n", __func__, __LINE__, data);
#endif
	
	return &state->frontend;

error3:
	kfree(state);
error2:
	return NULL;
}
EXPORT_SYMBOL(ds2000_attach);

/* Put device to sleep */
static int ds2000_sleep(struct dvb_frontend *fe)
{
	dprintk("%s()\n", __func__);
	
	return 0;
}

static struct dvb_frontend_ops ds2000_ops = {

	.info = {
		.name = "Montage Technology ds2000/RS2000",
		.type = FE_QPSK,
		.frequency_min = 950000,
		.frequency_max = 2150000,
		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
		.frequency_tolerance = 5000,
		.symbol_rate_min = 1000000,
		.symbol_rate_max = 45000000,
		.caps = FE_CAN_INVERSION_AUTO |
			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
			FE_CAN_2G_MODULATION |
			FE_CAN_QPSK | FE_CAN_RECOVER
	},

	.release = ds2000_release,

	.init = ds2000_initfe,
	//.release = ds2000_release,
	.sleep = ds2000_sleep,
	.read_status = ds2000_read_status,
	.read_ber = ds2000_read_ber,
	.read_signal_strength = ds2000_read_signal_strength,
	.read_snr = ds2000_read_snr,
	.read_ucblocks = ds2000_read_ucblocks,
	.set_tone = ds2000_set_tone,
	.diseqc_send_master_cmd = ds2000_send_diseqc_msg,
	.diseqc_send_burst = ds2000_diseqc_send_burst,
	.get_frontend_algo = ds2000_get_algo,

	.set_property = ds2000_set_property,
	.get_property = ds2000_get_property,
	.set_voltage  = ds2000_set_voltage,
	.set_frontend = ds2000_tune,
};

module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");

MODULE_DESCRIPTION("DVB Frontend module for Montage Technology "
			"DS2000/RS2000 hardware");
MODULE_AUTHOR("Wayman Qi");
MODULE_LICENSE("GPL");
